# Copyright (c) 2008 Todd A. Fisher
require 'esi/parser'
require 'esi/response'

module ESI
  class Processor
    attr_reader :config, :router

    include ESI::Log

    def initialize( config, router )
      @config = config
      @router = router
      @chunk_count = 0
      @chunk_size = @config[:chunk_size] || 4096
      @max_depth = @config[:max_depth] || 3
      @chunk_buffer = StringIO.new # when buffer reaches chunk_size write to the http_response socket
      @parser = ESI::Parser.new( @chunk_buffer, @router, @config.cache, @max_depth )
    end
    
    def send_head( http_response, status )

      http_response.header["Transfer-Encoding"] = "chunked"
      # this is the important part, rather then send the whole document back we send in chunks
      # each fragment is roughly in it's own chunk, this does mean we require http 1.1, chunk size is still a limit
      header = Mongrel::Const::STATUS_FORMAT % [status, Mongrel::HTTP_STATUS_CODES[status]]
      header.gsub!(/Connection: close\r\n/,'')
      http_response.header.out.rewind
      header << http_response.header.out.read + Mongrel::Const::LINE_END
      header.gsub!(/Status:.*?\r\n/,'')
      http_response.write( header )

      #print header

    end

    def send_body( http_request, params, http_response, proxy_response )
      
      @http_response = http_response

      # prepare the parser given the raw request params and the preprocessed request params
      @parser.prepare( http_request.params, params ) do|chars|
        if @parser.response.active_buffer.closed_write?
          @parser.response.open_active_buffer
          @parser.response.send
        end
        @parser.response.active_buffer << chars
        if @chunk_buffer.size > @chunk_size
          send_chunk
          @chunk_buffer = StringIO.new
          @parser.response.update_output( @chunk_buffer )
        end
      end

      #timer = Time.now
      # feed data to the parser
      proxy_response.read_body { |data| @parser.process data }
      #puts "processing time: #{Time.now - timer}"

      #timer = Time.now
      # finish the request
      @parser.finish 
      #puts "finish time: #{Time.now - timer}"

      send_chunk

      @chunk_count
    rescue => e
      STDERR.puts "\n#{e.message}: #{e.backtrace.join("\n")}\n"
    ensure 
      http_response.write( "0\r\n\r\n" )
      http_response.done = true
    end

    def send_chunk
      @chunk_buffer.rewind
      size = @chunk_buffer.size
      chunk_header = "#{"%x" % size}" + Mongrel::Const::LINE_END
      #puts chunk_header.inspect
      @http_response.write( chunk_header )  # write the chunk size
      #puts buffer.inspect
      @http_response.write( @chunk_buffer.read + Mongrel::Const::LINE_END )  # write the chunk

      @chunk_count += 1
    end

  end
end
